package com.zmn.plat.dubbo.impl.channel;

import com.alibaba.fastjson.JSONObject;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto.VtDTO;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.manager.common.database.annotation.ReadOnlyConnection;
import com.zmn.manager.redis.lock.DistributedLock;
import com.zmn.manager.redis.lock.DistributedLockUtils;
import com.zmn.plat.business.interfaces.channel.ChannelBService;
import com.zmn.plat.business.interfaces.channel.ChannelOrderConfigBService;
import com.zmn.plat.common.constant.RedisKeyConstant;
import com.zmn.plat.common.dto.channel.ChannelOrderConfigDIO;
import com.zmn.plat.common.dto.channel.ChannelOrderConfigDRO;
import com.zmn.plat.common.dto.channel.ChannelSimpleDRO;
import com.zmn.plat.common.dto.channel.ChannelWorkOrderTypeDRO;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.dubbo.interfaces.channel.ChannelOrderConfigListRemoteService;
import com.zmn.plat.dubbo.utils.DubboConsts;
import com.zmn.plat.manager.dictionary.ChannelDict;
import com.zmn.plat.model.entity.channel.Channel;
import com.zmn.plat.model.entity.channel.ChannelCombinationQuery;
import com.zmn.plat.model.entity.channel.ChannelSimpleVO;
import com.zmn.plat.model.entity.channel.order.config.ChannelOrderConfig;
import com.zmn.plat.model.entity.channel.order.config.ChannelOrderConfigQuery;
import com.zmn.plat.services.interfaces.channel.ChannelService;
import com.zmn.plat.services.interfaces.channel.order.config.ChannelOrderConfigService;
import com.zmn.plat.utils.bean.BeanCopyUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 描述: 渠道订单配置dubbo接口实现类
 *
 * @author linfeng
 * @since: 2020/11/04 11:02
 */
@Slf4j
@Service(version = DubboConsts.INTERFACE_VERSION, validation = "true")
public class ChannelOrderConfigListRemoteServiceImpl implements ChannelOrderConfigListRemoteService {

    @Resource
    private ChannelOrderConfigService channelOrderConfigService;

    @Resource
    private ChannelOrderConfigBService channelOrderConfigBusinessService;

    @Resource
    private ChannelService channelService;

    @Resource
    private ChannelBService channelBService;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    @ReadOnlyConnection
    public ResponseDTO<ChannelOrderConfigDRO> getByChannelId(Integer channelId) {

        log.info("ChannelOrderConfigListRemoteServiceImpl.getByChannelId参数channelId：{}", channelId);
        String key = RedisKeyConstant.getKeyChannelOrderConfigDro(channelId);
        String value = redisTemplate.opsForValue().get(key);
        // 缓存中有数据
        if (StringUtil.isNotBlank(value)) {
            try{
                ChannelOrderConfigDRO config = JSONObject.parseObject(value, ChannelOrderConfigDRO.class);
                return ResponseDTO.success(config, "OK");
            } catch (Exception e) {
                return ResponseDTO.fail(value);
            }
        }
        int time = 30;
        String lockKey = RedisKeyConstant.getLockKeyChannelOrderConfigDro(channelId);
        DistributedLock redisLock = DistributedLockUtils.buildReentrantLock(lockKey, time);
        if (redisLock.tryLock()) {
            try {
                ResponseDTO<ChannelOrderConfigDRO> response = getByChannelIdDataBase(channelId);
                if (response.isSuccess()) {
                    value = JSONObject.toJSONString(response.getData());
                } else {
                    value = response.getMessage();
                }
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.MINUTES);
                return response;
            } finally {
                try {
                    redisLock.unlock();
                } catch (Exception ignored) {}
            }
        } else {
            if (redisLock.lock(time, TimeUnit.SECONDS)) {
                try {
                    redisLock.unlock();
                } catch (Exception ignored) {}
                return getByChannelId(channelId);
            } else {
                log.error("根据渠道ID查询渠道订单配置，获取redis锁超时");
                return ResponseDTO.fail("根据渠道ID查询渠道订单配置，获取redis锁超时");
            }
        }
    }

    @Override
    public ResponseDTO<List<ChannelOrderConfigDRO>> listQuery(ChannelOrderConfigDIO orderConfigDIO) {
        ChannelOrderConfigQuery query = new ChannelOrderConfigQuery();
        BeanMapper.copy(orderConfigDIO, query);
        List<ChannelOrderConfig> channelOrderConfigs = channelOrderConfigService.listByQuery(query);

        List<ChannelOrderConfigDRO> result = new ArrayList<>();
        BeanCopyUtils.copyProperties(channelOrderConfigs, result);
        return ResponseDTO.success(result);
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<ChannelWorkOrderTypeDRO> getWorkOrderTypeByChannelId(Integer channelId) {
        log.info("ChannelOrderConfigListRemoteServiceImpl.getWorkOrderTypeByChannelId参数channelId：{}", channelId);

        try {
            ChannelWorkOrderTypeDRO result = channelOrderConfigBusinessService.getWorkOrderTypeByChannelId(channelId);
            return ResponseDTO.success(result);
        } catch (PlatException e) {
            return ResponseDTO.fromErrorCodeTable(e.getErrorCode());
        } catch (Exception e) {
            log.error("getWorkOrderTypeByChannelId参数channelId：{}，异常：", channelId, e);
            return ResponseDTO.fail(GlobalConsts.FAILD_MSG);
        }
    }


    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<VtDTO>> listVtByAppliqueAndRank(Integer applique, Integer rank) {
        log.info("ChannelListRemoteServiceImpl.listVtByApplique参数applique：{}，rank：{}", applique, rank);

        if (NumberUtil.isNullOrZero(applique)) {
            return ResponseDTO.fail("是否允许贴花参数不能为空");
        }

        if (NumberUtil.isNullOrZero(rank)) {
            return ResponseDTO.fail("渠道层级不能为空");
        }

        List<VtDTO> result = channelService.listVtByAppliqueAndRank(applique, rank);

        if (CollectionUtil.isNotNullOrEmpty(result)) {
            return ResponseDTO.success(result);
        }

        return ResponseDTO.success(Collections.EMPTY_LIST);
    }

        @Override
    @ReadOnlyConnection
    public ResponseDTO<Boolean> checkNotifyEngineer(Integer channelId) {
        log.info("checkNotifyEngineer参数channelId：{}", channelId);
        try {
            boolean flag = channelBService.checkNotifyEngineer(channelId);
            return ResponseDTO.success(flag);
        } catch (PlatException ex) {
            return ResponseDTO.fromErrorCodeTable(ex.getErrorCode());
        } catch (Exception e) {
            log.error("error：", e);
            return ResponseDTO.fail("系统错误! 调用失败!");
        }
    }

    @NotNull
    private ResponseDTO<ChannelOrderConfigDRO> getByChannelIdDataBase(Integer channelId) {

        ChannelOrderConfig channelOrderConfig = Optional.ofNullable(channelOrderConfigService.findByKey(channelId)).orElse(null);
        ChannelOrderConfigDRO channelOrderConfigDro = new ChannelOrderConfigDRO();
        if (!Objects.isNull(channelOrderConfig)) {
            BeanCopyUtils.copyProperties(channelOrderConfig, channelOrderConfigDro);
            return ResponseDTO.success(channelOrderConfigDro, "OK");
        }
        Channel channel = channelService.findByKey(channelId);
        if (Objects.isNull(channel)) {
            return ResponseDTO.fail("渠道不存在");
        }
        if (ChannelDict.RANK_ONE == channel.getRank() || null == channel.getParentId()) {
            return ResponseDTO.fail("没有相关渠道配置信息");
        }
        channelOrderConfig = Optional.ofNullable(channelOrderConfigService.findByKey(channel.getParentId())).orElse(null);
        if (Objects.isNull(channelOrderConfig)) {
            return ResponseDTO.fail("没有相关渠道配置信息");
        }
        BeanCopyUtils.copyProperties(channelOrderConfig, channelOrderConfigDro);
        return ResponseDTO.success(channelOrderConfigDro, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<ChannelSimpleDRO>> listByChannelOrderConfigDIO(ChannelOrderConfigDIO channelOrderConfigDIO) {
        log.info("ChannelListRemoteServiceImpl.listByChannelOrderConfigDIO参数channelOrderConfigDIO：{}", channelOrderConfigDIO);

        if (Objects.isNull(channelOrderConfigDIO)) {
            log.error("参数不能为空");
            return ResponseDTO.fail("参数不能为空");
        }

        ChannelCombinationQuery query = new ChannelCombinationQuery();
        BeanCopyUtils.copyProperties(channelOrderConfigDIO, query);
        List<ChannelSimpleVO> result = channelService.listByCombinationQuery(query);
        List<ChannelSimpleDRO> dros = BeanMapper.mapList(result, ChannelSimpleDRO.class);

        return ResponseDTO.success(dros);
    }


    @Override
    @ReadOnlyConnection
    public ResponseDTO<Boolean> checkShowOrderPrice(Integer channelId) {
        log.info("checkNotifyEngineer参数channelId：{}", channelId);
        try {
            boolean flag = channelBService.checkShowOrderPrice(channelId);
            return ResponseDTO.success(flag);
        } catch (PlatException ex) {
            return ResponseDTO.fromErrorCodeTable(ex.getErrorCode());
        } catch (Exception e) {
            log.error("error：", e);
            return ResponseDTO.fail("系统错误! 调用失败!");
        }
    }
}
